const {
	ENUM_NOTIFICATION_TYPE
} = require("../../static/enum");
const Notification = require('./models/notification.js');
const {
	getUUID
} = require("../utils/index.js");

const __notificationList = {}; // 通知存储器

/**
 * 发送 Notice 广播
 * @param {string} name 广播名称
 * @param {any} info 附带信息
 */
function postNotification(name, info) {
	if (name === null || name === undefined || typeof name !== 'string') {
		throw new Error('postNotification 请传入 string 类型的 notice name')
	}
	const notification = __notificationList[name];
	// 是否存在 name 对应的通知对象
	if (notification === null || notification === undefined) { // 不存在，跳出
		return;
	}
	// 存在通知对象
	// 判断通知对象 通知模式类型
	if (notification.notificationType === ENUM_NOTIFICATION_TYPE.NORMAL) { // 正常模式， 循环通知所有监听者
		notification.notificationObserverList.forEach(item => {
			item.selector.call(item.observerSymbol, info);
		})
	} else if (notification.notificationType === ENUM_NOTIFICATION_TYPE.FRIST) { // 保留最老模式，监听列表中只有一位，通知第一位
		let item = notification.notificationObserverList[0];
		if (item) {
			item.selector.call(item.observerSymbol, info);
		}
	} else if (notification.notificationType === ENUM_NOTIFICATION_TYPE.LAST) { // 通知最新模式，查找监听列表最后一位，调用响应方法响应通知
		let item = notification.notificationObserverList[notification.notificationObserverList.length - 1];
		if (item) {
			item.selector.call(item.observerSymbol, info)
		}
	}
}

/**
 * 移除 Notice 广播
 * @param {string} name 广播名称
 * @param {any} observerSymbol 监听对象标志 监听者为空时，移除 该 Notice 下所有监听者
 */
function removeNotificationObserver(name, observerSymbol) {
	// 是否有 name 对应的 通知对象
	if (__notificationList[name] !== null) {
		// 监听者 是否为空 
		if (observerSymbol === null || observerSymbol === undefined) { // 如果为空，清除 notice 下所有监听者
			__notificationList[name].removeAllObserver()
		} else { // 如果不为空，移除对应的 监听者
			__notificationList[name].removeObserver(observerSymbol);
		}
	}
}

/**
 * 添加 Notice 监听
 * @param {string} name 广播名称
 * @param {function} selector 响应方法
 * @param {any} observerSymbol 监听者标志
 * @param {ENUM_NOTIFICATION_TYPE} notificationType 通知类型
 * @returns 返回监听者标志
 */
// 添加通知观察者
function addNotificationObserver(name, selector, observerSymbol, notificationType) {
	// 判断 name 是否为空或者不是字符串类型
	if (name === null || name === undefined || typeof name !== 'string') {
		throw new Error('addNotificationObserver 请传入 string 类型的 notice 广播名称 name');
	}
	// 判断 selector 是否为空或者不是函数类型
	if (selector === null || selector === undefined || typeof selector !== 'function') {
		throw new Error('addNotificationObserver 请传入 function 类型的 notice 响应方法 selector');
	}
	// 判断 observerSymbol 是否为空
	if (observerSymbol === null || observerSymbol === undefined) {
		observerSymbol = getUUID();
	}
	// 如果不存在该 通知， 创建通知
	if (__notificationList[name] === null || __notificationList[name] === undefined) {
		__notificationList[name] = new Notification(name, notificationType);
	} else {
		// 如果存在该 通知， 判断通知类型是否一致
		if (__notificationList[name].notificationType !== notificationType) {
			throw new Error(
				`存在相同名称：${name}, 但不同类型的通知 ${__notificationList[name].notificationType} | ${notificationType}, 同一通知名称仅应存在一种通知类型！`
			);
		}
	}
	// 插入通知的监听者
	return __notificationList[name].addObserver(selector, observerSymbol);
}

/**
 * 添加 保持最新通知监听者 通知
 * @param {string} name 通知名称
 * @param {function} selector 响应方法
 * @param {any} observerSymbol 监听对象标志
 * @returns 返回监听者标志
 */
function addLastNotificationObserver(name, selector, observerSymbol) {
	return addNotificationObserver(name, selector, observerSymbol, ENUM_NOTIFICATION_TYPE.LAST);
}

/**
 * 添加 保持最原始监听者 通知
 * @param {string} name 通知名称
 * @param {function} selector 响应方法
 * @param {any} observerSymbol 监听对象标志
 * @returns 返回监听者标志
 */
function addFristNotificationObserver(name, selector, observerSymbol) {
	return addNotificationObserver(name, selector, observerSymbol, ENUM_NOTIFICATION_TYPE.FRIST);
}

/**
 * 添加 多个通知监听者 通知
 * @param {string} name 通知名称
 * @param {function} selector 响应方法
 * @param {any} observerSymbol 监听对象标志
 * @returns 返回监听者标志
 */
function addNormalNotificationObserver(name, selector, observerSymbol) {
	return addNotificationObserver(name, selector, observerSymbol, ENUM_NOTIFICATION_TYPE.NORMAL);
}

/**
 * 导出通知列表 用以调试
 * @returns 通知列表
 */
function exportNotificationList() {
	return __notificationList;
}

module.exports = {
	postNotification,

	removeNotificationObserver,

	addLastNotificationObserver,
	addFristNotificationObserver,
	addNormalNotificationObserver,

	exportNotificationList
}